package com.yy.wga.mp.module.income.manager;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.yy.wga.mp.module.income.entity.pojo.IncomeOrderGoodsDO;
import com.yy.wga.mp.module.income.entity.pojo.IncomeUserBalanceDO;
import com.yy.wga.mp.module.income.service.IncomeOrderGoodsService;
import com.yy.wga.mp.module.income.service.IncomeUserBalanceService;
import com.yy.wga.common.core.exception.BusinessException;
import com.yy.wga.mp.common.utils.common.StringUtils;
import com.yy.wga.mp.common.utils.mapping.BeansUtils;
import com.yy.wga.mp.module.goods.common.utils.CommissionUtil;
import com.yy.wga.mp.module.income.dto.OrderCommissionDTO;
import com.yy.wga.mp.module.user.entity.pojo.UserBaseDO;
import com.yy.wga.mp.module.user.entity.pojo.UserRelationDO;
import com.yy.wga.mp.module.user.entity.pojo.UserSummaryDO;
import com.yy.wga.mp.module.user.enums.EUserGrade;
import com.yy.wga.mp.module.user.events.OrderSettleEvent;
import com.yy.wga.mp.module.user.service.UserBaseService;
import com.yy.wga.mp.module.user.service.UserRelationService;
import com.yy.wga.mp.module.user.service.UserSummaryService;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.context.ApplicationEventPublisher;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;

import java.math.BigDecimal;
import java.util.*;
import java.util.stream.Collectors;

/**
 * @Author: gc
 * @Date: 2024/11/12
 * @Description:
 **/
@Slf4j
@Service
@RequiredArgsConstructor
public class OrderCommissionManager {

    private final UserRelationService userRelationService;
    private final IncomeOrderGoodsService incomeOrderGoodsService;
    private final IncomeUserBalanceService incomeUserBalanceService;
    private final UserBaseService userBaseService;
    private final UserSummaryService userSummaryService;
    private final ApplicationEventPublisher eventPublisher;

    @Transactional
    public void commission(OrderCommissionDTO orderCommissionDTO) {
        if (orderCommissionDTO.getFromUserId() == null
                && orderCommissionDTO.getShareUserId() == null) {
            throw new BusinessException("分享用户和购买用户id必填一个");
        }
        // 订单状态 1、待支付 2、下单成功 3、待发货 4、已发货 5、已取消 6、已收货 7、已结算
        int status = orderCommissionDTO.getStatus();
        if (status == 1) {
            return;
        }
        // 转换订单状态为收益状态
        // 收益状态 1、待结算 2、已结算 3已取消
        Integer incomeStatus;
        if (status == 5){
            incomeStatus = 3;
        } else if (Arrays.asList(2, 3, 4, 6).contains(status)) {
            incomeStatus = 1;
        } else {
            log.error("订单状态无法转换成收益状态,orderNo:{}, status:{}", orderCommissionDTO.getOrderNo(), status);
            return;
        }

        // 已分佣则是修改，否则新增
        List<IncomeOrderGoodsDO> incomeOrderList = incomeOrderGoodsService.list(new LambdaQueryWrapper<IncomeOrderGoodsDO>()
                .eq(IncomeOrderGoodsDO::getAppKey, orderCommissionDTO.getAppKey())
                .eq(IncomeOrderGoodsDO::getOrderNo, orderCommissionDTO.getOrderNo()));
        if (!CollectionUtils.isEmpty(incomeOrderList)) {
            for (IncomeOrderGoodsDO incomeOrderGoodsDO : incomeOrderList) {
                if (incomeStatus.equals(incomeOrderGoodsDO.getStatus())) {
                    continue;
                }
                // 如果是待结算，但是之前已经存在收益记录了，所以不需要处理
                if (incomeStatus == 1) {
                    continue;
                }
                // 剩下的收益状态只会为取消
                IncomeUserBalanceDO userBalance = new IncomeUserBalanceDO();
                userBalance.setUserId(incomeOrderGoodsDO.getUserId());
                userBalance.setAppKey(incomeOrderGoodsDO.getAppKey());
                userBalance.setCancel(incomeOrderGoodsDO.getCommissionValue());
                // 移除之前的收益
                if (incomeOrderGoodsDO.getStatus() == 2) {
                    userBalance.setSettle(-incomeOrderGoodsDO.getCommissionValue());
                } else if (incomeOrderGoodsDO.getStatus() == 1) {
                    userBalance.setUnSettle(-incomeOrderGoodsDO.getCommissionValue());
                }
                incomeUserBalanceService.incrementIncome(userBalance);
            }
            // 修改收益状态
            incomeOrderGoodsService.update(new LambdaUpdateWrapper<IncomeOrderGoodsDO>()
                    .in(IncomeOrderGoodsDO::getId, incomeOrderList.stream()
                            .map(IncomeOrderGoodsDO::getId).collect(Collectors.toSet()))
                    .set(IncomeOrderGoodsDO::getStatus, incomeStatus)
                    .set(incomeStatus.equals(1), IncomeOrderGoodsDO::getPayTime, orderCommissionDTO.getPayTime())
                    .set(incomeStatus.equals(1), IncomeOrderGoodsDO::getSuccessTime, orderCommissionDTO.getSuccessTime())
                    .set(incomeStatus.equals(3), IncomeOrderGoodsDO::getCancelTime, orderCommissionDTO.getCancelTime()));
            return;
        }

        // 分佣链路
        long commissionUserId = orderCommissionDTO.getShareUserId() != null
                ? orderCommissionDTO.getShareUserId() : orderCommissionDTO.getFromUserId();
        List<UserRelationDO> userRelationLink = this.getUserRelationLink(orderCommissionDTO.getAppKey(), commissionUserId);
        // 没有分佣链路则不分佣
        if (CollectionUtils.isEmpty(userRelationLink)) {
            log.info("{}无分佣链路", orderCommissionDTO.getFromUserId());
            return;
        }

        // 分佣
        List<EUserGrade> commissionLink = EUserGrade.getCommissionLink();
        BigDecimal accumulationRate = BigDecimal.ZERO;
        int minGrade = EUserGrade.COMMON.getType();
        int minLevel = EUserGrade.COMMON.getLevel();;
        List<IncomeOrderGoodsDO> incomeList = new ArrayList<>(commissionLink.size());
        for (int i = 0; i < userRelationLink.size(); i++) {
            UserRelationDO userRelation = userRelationLink.get(i);
            // 小于之前的等级不进行分佣
            if (userRelation.getParentGrade() < minGrade) {
                continue;
            }
            // 相同等级但是级别没有大于之前的级别，也不进行分佣
            if (userRelation.getParentGrade() == minGrade
                    && userRelation.getParentLevel() <= minLevel) {
                continue;
            }
            minGrade = userRelation.getParentGrade();
            minLevel = userRelation.getParentLevel();
            // 遍历等级链路，找到对应的分佣等级，并累积极差佣金
            for (Iterator<EUserGrade> it = commissionLink.iterator(); it.hasNext(); ) {
                EUserGrade userGrade = it.next();
                accumulationRate = accumulationRate.add(userGrade.getBuyCommissionRate());
                if (userGrade.getType() != minGrade || userGrade.getLevel() != minLevel) {
                    it.remove();
                } else {
                    // 匹配命中未删除选中等级，等分佣完成再删
                    break;
                }
            }
            // 进行分佣
            Integer commission = CommissionUtil.getCommission(orderCommissionDTO.getCommissionValue(), accumulationRate);
            IncomeOrderGoodsDO income = BeansUtils.map(orderCommissionDTO, IncomeOrderGoodsDO.class);
            income.setUserId(userRelation.getParentUserId());
            income.setCommissionValue(commission);
            income.setType(1);
            income.setStatus(incomeStatus);
            incomeList.add(income);
            accumulationRate = BigDecimal.ZERO;

            // 增加用户余额
            IncomeUserBalanceDO userBalance = new IncomeUserBalanceDO();
            userBalance.setAppKey(orderCommissionDTO.getAppKey());
            userBalance.setUserId(income.getUserId());
            if (incomeStatus == 1) {
                userBalance.setUnSettle(income.getCommissionValue());
            } else {
                userBalance.setCancel(income.getCommissionValue());
            }
            incomeUserBalanceService.incrementIncome(userBalance);

            // 直推人收益
            if (i < userRelationLink.size() - 1) {
                UserRelationDO parentUserRelation = userRelationLink.get(i + 1);
                IncomeOrderGoodsDO directIncome = BeansUtils.map(income, IncomeOrderGoodsDO.class);
                EUserGrade directUserGrade = EUserGrade.getByType(parentUserRelation.getParentGrade(), parentUserRelation.getParentLevel());
                directIncome.setCommissionValue(CommissionUtil.getDirectCommission(income.getCommissionValue(), directUserGrade.getDirectCommissionRate()));
                directIncome.setUserId(parentUserRelation.getParentUserId());
                directIncome.setType(2);
                incomeList.add(directIncome);

                // 增加用户余额
                userBalance = new IncomeUserBalanceDO();
                userBalance.setAppKey(orderCommissionDTO.getAppKey());
                userBalance.setUserId(directIncome.getUserId());
                if (incomeStatus == 1) {
                    userBalance.setUnSettle(directIncome.getCommissionValue());
                } else {
                    userBalance.setCancel(directIncome.getCommissionValue());
                }
                incomeUserBalanceService.incrementIncome(userBalance);
            }

            // 分佣完移除该等级，如果移除后无分佣等级，则跳出分佣
            if (!commissionLink.isEmpty()) {
                commissionLink.remove(0);
            }
            if (commissionLink.isEmpty()) {
                break;
            }
        }
        incomeOrderGoodsService.saveBatch(incomeList);

        // 增加用户销售额
        Long fromUserId = orderCommissionDTO.getShareUserId() != null
                ? orderCommissionDTO.getShareUserId() : orderCommissionDTO.getFromUserId();
        UserSummaryDO userSummaryDO = new UserSummaryDO();
        userSummaryDO.setAppKey(orderCommissionDTO.getAppKey());
        userSummaryDO.setSaleAmount(orderCommissionDTO.getFinalPrice());
        userSummaryDO.setUserId(fromUserId);
        userSummaryService.updateInfo(userSummaryDO);

        // 事件通知，消费金额升级等级
        OrderSettleEvent orderSettleEvent = new OrderSettleEvent(this);
        orderSettleEvent.setUserId(fromUserId);
        orderSettleEvent.setAppKey(orderCommissionDTO.getAppKey());
        eventPublisher.publishEvent(orderSettleEvent);
    }

    /**
     * 查询整条分佣链路
     * @param appKey
     * @param fromUserId
     * @return
     */
    private List<UserRelationDO> getUserRelationLink(String appKey, long fromUserId) {
        List<UserRelationDO> userRelationList = new LinkedList<>();
        // 如果不是普通用户，新增下单人等级到关系链中
        UserBaseDO formUserBase = userBaseService.getOne(new LambdaQueryWrapper<UserBaseDO>()
                .eq(UserBaseDO::getAppKey, appKey)
                .eq(UserBaseDO::getId, fromUserId));
        if (!formUserBase.getGrade().equals(EUserGrade.COMMON.getType())) {
            UserRelationDO fromUserRelation = new UserRelationDO();
            fromUserRelation.setParentUserId(formUserBase.getId());
            fromUserRelation.setParentGrade(formUserBase.getGrade());
            fromUserRelation.setParentLevel(formUserBase.getLevel());
            userRelationList.add(fromUserRelation);
        }

        Set<Long> allUserIds = new HashSet<>();
        // 查询关系链
        long childUserId = fromUserId;
        while (true) {
            UserRelationDO userRelationDO = userRelationService.getOne(new LambdaQueryWrapper<UserRelationDO>()
                    .eq(UserRelationDO::getAppKey, appKey)
                    .eq(UserRelationDO::getUserId, childUserId));
            if (userRelationDO == null) {
                break;
            }
            childUserId = userRelationDO.getParentUserId();
            userRelationList.add(userRelationDO);
            if (allUserIds.contains(childUserId)) {
                log.error("关系链死锁了:{}", StringUtils.join(",", allUserIds));
                break;
            }
            allUserIds.add(childUserId);
        }
        return userRelationList;
    }
}
